home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / pdcurs21 / private / _vsscanf.c < prev    next >
C/C++ Source or Header  |  1993-06-18  |  13KB  |  442 lines

  1. /*
  2.  * This module is based on vsscanf.c and input.c from emx 0.8f library
  3.  * source which is Copyright (c) 1990-1992 by Eberhard Mattes.
  4.  * Eberhard Mattes has kindly agreed to allow this module to be incorporated
  5.  * into PDCurses.
  6.  */
  7. #ifdef PDCDEBUG
  8. char *rcsid__vsscanf = "$Header: C:\CURSES\private\RCS\_vsscanf.c 2.1 1993/06/18 20:22:49 MH Rel MH $";
  9. #endif
  10.  
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stdarg.h>
  15. #include <string.h>
  16. #include <limits.h>
  17. #include <ctype.h>
  18.  
  19. #define TRUE 1
  20. #define FALSE 0
  21.  
  22. #define WHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
  23.  
  24. #define NEXT(x) \
  25.         do { \
  26.             x = *buf++; \
  27.             if (x == '\0') \
  28.                return (count == 0 ? EOF : count); \
  29.             ++chars; \
  30.            } while (0)
  31.  
  32. #define UNGETC(x) \
  33.         do { \
  34.             --buf; *buf = x; --chars; \
  35.            } while (0)
  36.  
  37. /*man-start*********************************************************************
  38.  
  39.   PDC_vsscanf()    - Internal routine to parse and format an input buffer.
  40.  
  41.   PDCurses Description:
  42.      This is a private PDCurses routine.
  43.  
  44.      Scan a series of input fields. Each field is formatted according to
  45.      a supplied format string and the formatted input is stored in the
  46.      variable number of addresses passed.
  47.  
  48.   PDCurses Return Value:
  49.      This function returns the number of input fields or EOF on error.
  50.  
  51.   PDCurses Errors:
  52.      If the supplied data is invalid or an incorrect number of arguments
  53.      are passed, EOF is returned as an error.
  54.  
  55.   Portability:
  56.      PDCurses    int PDC_vsscanf(char *buf,const char *fmt,va_list arg_ptr);
  57.  
  58. **man-end**********************************************************************/
  59.  
  60. int PDC_vsscanf ( char *buf, const char *fmt, char *arg_ptr)
  61. {
  62.     int count, chars, c, width, radix, d, i;
  63.     int *int_ptr;
  64.     long *long_ptr;
  65.     short *short_ptr;
  66.     char *char_ptr;
  67.     unsigned char f;
  68.     char neg, assign, ok, size;
  69.     unsigned long n;
  70.     char map[256], end;
  71.     double dx, dd, *dbl_ptr;
  72.     float *flt_ptr;
  73.     int exp;
  74.     char eneg;
  75.  
  76. #ifdef PDCDEBUG
  77. #define bool unsigned char
  78.     extern bool trace_on; /* this is explicit here as curses.h is not #included */
  79.     if (trace_on) PDC_debug("PDC_vsscanf() - called\n");
  80. #endif
  81.  
  82.   count = 0; chars = 0; c = 0;
  83.   while ((f = *fmt) != 0)
  84.     {
  85.       if (WHITE (f))
  86.         {
  87.           do
  88.             {
  89.               ++fmt; f = *fmt;
  90.             } while (WHITE (f));
  91.           do
  92.             {
  93.               c = *buf++;
  94.               if (c == '\0')
  95.                 {
  96.                   if (f == 0 || count != 0)
  97.                     return (count);
  98.                   else
  99.                     return (EOF);
  100.                 }
  101.               else
  102.                 ++chars;
  103.             } while (WHITE (c));
  104.           UNGETC (c);
  105.         }
  106.       else if (f != '%')
  107.         {
  108.           NEXT (c);
  109.           if (c != f)
  110.             return (count);
  111.           ++fmt;
  112.         }
  113.       else
  114.         {
  115.           assign = TRUE; width = INT_MAX;
  116.           char_ptr = NULL;
  117.           ++fmt;
  118.           if (*fmt == '*')
  119.             {
  120.               assign = FALSE;
  121.               ++fmt;
  122.             }
  123.           if (isdigit (*fmt))
  124.             {
  125.               width = 0;
  126.               while (isdigit (*fmt))
  127.                 width = width * 10 + (*fmt++ - '0');
  128.               if (width == 0) width = INT_MAX;
  129.             }
  130.           size = 0;
  131.           if (*fmt == 'h' || *fmt == 'l')
  132.             size = *fmt++;
  133.           f = *fmt;
  134.           switch (f)
  135.             {
  136.             case 'c':
  137.               if (width == INT_MAX)
  138.                 width = 1;
  139.               if (assign)
  140.                 char_ptr = va_arg (arg_ptr, char *);
  141.               while (width > 0)
  142.                 {
  143.                   --width;
  144.                   NEXT (c);
  145.                   if (assign)
  146.                     {
  147.                       *char_ptr++ = (char)c;
  148.                       ++count;
  149.                     }
  150.                 }
  151.               break;
  152.             case '[':
  153.               (void)memset (map, 0, 256);
  154.               end = 0;
  155.               ++fmt;
  156.               if (*fmt == '^')
  157.                 {
  158.                   ++fmt; end = 1;
  159.                 }
  160.               i = 0;
  161.               for (;;)
  162.                 {
  163.                   f = (unsigned char)*fmt;
  164.                   switch (f)
  165.                     {
  166.                     case 0:
  167.                       --fmt;       /* avoid skipping past 0 */
  168.                       NEXT (c);
  169.                       goto string;
  170.                     case ']':
  171.                       if (i > 0)
  172.                         {
  173.                           NEXT (c);
  174.                           goto string;
  175.                         }
  176.                       /* no break */
  177.                     default:
  178.                       if (fmt[1] == '-' && fmt[2] != 0 &&
  179.                           f < (unsigned char)fmt[2])
  180.                         {
  181.                           (void)memset (map+f, 1, (unsigned char)fmt[2]-f);
  182.                           fmt += 2;
  183.                         }
  184.                       else
  185.                         map[f] = 1;
  186.                       break;
  187.                     }
  188.                   ++fmt; ++i;
  189.                 }
  190.             case 's':
  191.               (void)memset (map, 0, 256);
  192.               map[' '] = 1;
  193.               map['\n'] = 1;
  194.               map['\r'] = 1;
  195.               map['\t'] = 1;
  196.               end = 1;
  197.               do
  198.                 {
  199.                   NEXT (c);
  200.                 } while (WHITE (c));
  201. string:
  202.               if (assign)
  203.                 char_ptr = va_arg (arg_ptr, char *);
  204.               while (width > 0 && map[(unsigned char)c] != end)
  205.                 {
  206.                   --width;
  207.                   if (assign)
  208.                     *char_ptr++ = (char)c;
  209.                   c = *buf++;
  210.                   if (c == '\0')
  211.                     break;
  212.                   else
  213.                     ++chars;
  214.                 }
  215.               if (assign)
  216.                 {
  217.                   *char_ptr = 0;
  218.                   ++count;
  219.                 }
  220.               if (c == '\0')
  221.                 return (count);
  222.               else
  223.                 UNGETC (c);
  224.               break;
  225.             case 'f':
  226.             case 'e':
  227.             case 'E':
  228.             case 'g':
  229.             case 'G':
  230.               neg = ok = FALSE; dx = 0.0;
  231.               do
  232.                 {
  233.                   NEXT (c);
  234.                 } while (WHITE (c));
  235.               if (c == '+')
  236.                 {
  237.                   NEXT (c); --width;
  238.                 }
  239.               else if (c == '-')
  240.                 {
  241.                   neg = TRUE; NEXT (c); --width;
  242.                 }
  243.               while (width > 0 && isdigit (c))
  244.                 {
  245.                   --width;
  246.                   dx = dx * 10.0 + (double)(c - '0');
  247.                   ok = TRUE;
  248.                   c = *buf++;
  249.                   if (c == '\0')
  250.                     break;
  251.                   else
  252.                     ++chars;
  253.                 }
  254.               if (width > 0 && c == '.')
  255.                 {
  256.                   --width;
  257.                   dd = 10.0; NEXT (c);
  258.                   while (width > 0 && isdigit (c))
  259.                     {
  260.                       --width;
  261.                       dx += (double)(c - '0') / dd;
  262.                       dd *= 10.0;
  263.                       ok = TRUE;
  264.                       c = *buf++;
  265.                       if (c == '\0')
  266.                         break;
  267.                       else
  268.                         ++chars;
  269.                     }
  270.                 }
  271.               if (!ok)
  272.                 return (count);
  273.               if (width > 0 && (c == 'e' || c == 'E'))
  274.                 {
  275.                   eneg = FALSE; exp = 0; NEXT (c); --width;
  276.                   if (width > 0 && c == '+')
  277.                     {
  278.                       NEXT (c); --width;
  279.                     }
  280.                   else if (width > 0 && c == '-')
  281.                     {
  282.                       eneg = TRUE; NEXT (c); --width;
  283.                     }
  284.                   if (!(width > 0 && isdigit (c)))
  285.                     {
  286.                       UNGETC (c);
  287.                       return (count);
  288.                     }
  289.                   while (width > 0 && isdigit (c))
  290.                     {
  291.                       --width;
  292.                       exp = exp * 10 + (c - '0');
  293.                       c = *buf++;
  294.                       if (c == '\0')
  295.                         break;
  296.                       else
  297.                         ++chars;
  298.                     }
  299.                   if (eneg) exp = -exp;
  300.                   while (exp > 0)
  301.                     {
  302.                       dx *= 10.0;
  303.                       --exp;
  304.                     }
  305.                   while (exp < 0)
  306.                     {
  307.                       dx /= 10.0;
  308.                       ++exp;
  309.                     }
  310.                 }
  311.               if (assign)
  312.                 {
  313.                   if (neg) dx = -dx;
  314.                   if (size == 'l')
  315.                     {
  316.                       dbl_ptr = va_arg (arg_ptr, double *);
  317.                       *dbl_ptr = dx;
  318.                     }
  319.                   else
  320.                     {
  321.                       flt_ptr = va_arg (arg_ptr, float *);
  322.                       *flt_ptr = (float)dx;
  323.                     }
  324.                   ++count;
  325.                 }
  326.               if (c == '\0')
  327.                 return (count);
  328.               else
  329.                 UNGETC (c);
  330.               break;
  331.             case 'i':
  332.               neg = FALSE; radix = 10;
  333.               do
  334.                 {
  335.                   NEXT (c);
  336.                 } while (WHITE (c));
  337.               if (!(width > 0 && c == '0'))
  338.                 goto scan_complete_number;
  339.               NEXT (c); --width;
  340.               if (width > 0 && (c == 'x' || c == 'X'))
  341.                 {
  342.                   NEXT (c); radix = 16; --width;
  343.                 }
  344.               else if (width > 0 && (c >= '0' && c <= '7'))
  345.                 radix = 8;
  346.               goto scan_unsigned_number;
  347.             case 'd':
  348.             case 'u':
  349.             case 'o':
  350.             case 'x':
  351.             case 'X':
  352.               do
  353.                 {
  354.                   NEXT (c);
  355.                 } while (WHITE (c));
  356.               switch (f)
  357.                 {
  358.                 case 'o':           radix = 8; break;
  359.                 case 'x': case 'X': radix = 16; break;
  360.                 default:            radix = 10; break;
  361.                 }
  362. scan_complete_number:
  363.               neg = FALSE;
  364.               if (width > 0 && c == '+')
  365.                 {
  366.                   NEXT (c); --width;
  367.                 }
  368.               else if (width > 0 && c == '-' && radix == 10)
  369.                 {
  370.                   neg = TRUE; NEXT (c); --width;
  371.                 }
  372. scan_unsigned_number:
  373.               n = 0; ok = FALSE;
  374.               while (width > 0)
  375.                 {
  376.                   --width;
  377.                   if (isdigit (c))
  378.                     d = c - '0';
  379.                   else if (isupper (c))
  380.                     d = c - 'A' + 10;
  381.                   else if (islower (c))
  382.                     d = c - 'a' + 10;
  383.                   else
  384.                     break;
  385.                   if (d < 0 || d >= radix)
  386.                     break;
  387.                   ok = TRUE;
  388.                   n = n * radix + d;
  389.                   c = *buf++;
  390.                   if (c == '\0')
  391.                     break;
  392.                   else
  393.                     ++chars;
  394.                 }
  395.               if (!ok)
  396.                 return (count);
  397.               if (assign)
  398.                 {
  399.                   if (neg) n = -n;
  400.                   switch(size)
  401.                      {
  402.                       case 'h':
  403.                               short_ptr = va_arg (arg_ptr, short *);
  404.                               *short_ptr = (short)n;
  405.                               break;
  406.                       case 'l':
  407.                               long_ptr = va_arg (arg_ptr, long *);
  408.                               *long_ptr = (long)n;
  409.                               break;
  410.                       default:
  411.                               int_ptr = va_arg (arg_ptr, int *);
  412.                               *int_ptr = (int)n;
  413.                      }
  414.                   ++count;
  415.                 }
  416.               if (c == '\0')
  417.                 return (count);
  418.               else
  419.                 UNGETC (c);
  420.               break;
  421.             case 'n':
  422.               if (assign)
  423.                 {
  424.                   int_ptr = va_arg (arg_ptr, int *);
  425.                   *int_ptr = chars;
  426.                   ++count;
  427.                 }
  428.               break;
  429.             default:
  430.               if (f == 0)                 /* % at end of string */
  431.                 return (count);
  432.               NEXT (c);
  433.               if (c != f)
  434.                 return (count);
  435.               break;
  436.             }
  437.           ++fmt;
  438.         }
  439.     }
  440.   return (count);
  441. }
  442.